﻿#light

/// <summary>
/// Defines the interface for implementation classes.
/// This interface doesn't have to correspond exactly
/// to Abstraction's interface; in fact, the two
/// interfaces can be quite different. Typically the
/// Implementation interface provides only primitive
/// operations and Abstraction defines higher-level
/// operations based on these primitives.
/// </summary>
type Implementor =
    abstract Operation : unit -> unit

/// <summary>
/// Defines the abstraction's interface.
/// Maintains a reference to an object of type Implementor.
/// </summary>
type Abstraction(implementor: Implementor) =
    let mutable impl = implementor
    
    member this.Implementor with get() = impl
                            and set v = impl <- v
    
    member this.Operation() =
        this.Implementor.Operation()
    
    interface Implementor with
        member this.Operation() =
            this.Operation()

/// <summary>
/// Extends the interface defined by Abstraction.
/// </summary>
type RefinedAbstraction(implementor: Implementor) =
    inherit Abstraction(implementor)
    
    interface Implementor with
        member this.Operation() =
            implementor.Operation()

/// <summary>
/// Implements the Implementor interface and defines
/// its concrete implementation.
/// </summary>
type ConcreteImplementorA() =
    interface Implementor with
        member this.Operation() =
            printfn "ConcreteImplementorA Operation"

/// <summary>
/// Implements the Implementor interface and defines
/// its concrete implementation.
/// </summary>
type ConcreteImplementorB() =
    interface Implementor with
        member this.Operation() =
            printfn "ConcreteImplementorB Operation"
